#pragma once
#include "list_base.h"
#include <string>

template <typename T>
class list: public list_base<T>
{
	struct node
	{
		T value;
		node *previous;
		node *next;
	};
	int number_of_nodes;
	node *head;
	node *tail;
public:
	typedef typename node* iterator;
	list() { number_of_nodes = 0; }
	virtual ~list();
	virtual void push_front(T elem);
	virtual void push_back(T elem);
	virtual const T front() { return head->value; }
	virtual const T back() { return tail->value; }
	virtual void pop_front();
	virtual void pop_back();
	virtual bool empty() { return (head == nullptr); }
	virtual int size() { return number_of_nodes; }
	virtual std::string show_all();
};

template<typename T>
list<T>::~list()
{
	if (head != nullptr)
	{
		node *temp;
		while (head != tail)
		{
			temp = head;
			head = head->next;
			delete temp;
		}
		delete head;
	}
}

template<typename T>
void list<T>::push_front(T elem)
{
	if (head == nullptr)
	{
		head = tail = new node;
	}
	else
	{
		head->previous = new node;
		head->previous->next = head;
		head = head->previous;
	}
	head->value = elem;
	number_of_nodes++;
}

template<typename T>
void list<T>::push_back(T elem)
{
	if (tail == nullptr)
	{
		head = tail = new node;
	}
	else
	{
		tail->next = new node;
		tail->next->previous = tail;
		tail = tail->next;
	}
	tail->value = elem;
	number_of_nodes++;
}

template<typename T>
void list<T>::pop_front()
{
	if (head == tail)
	{
		delete head;
	}
	else
	{
		node* temp = head;
		head = head->next;
		delete temp;
	}
	number_of_nodes--;
}

template<typename T>
void list<T>::pop_back()
{
	if (head == tail)
	{
		delete tail;
	}
	else
	{
		node* temp = tail;
		tail = tail->previous;
		delete temp;
	}
	number_of_nodes--;
}

template<typename T>
std::string list<T>::show_all()
{
	if (head != nullptr)
	{
		std::string result;
		node* i = head;
		do
		{
			result += std::to_string(i->value) + " ";
			i = i->next;
		}
		while (i != tail);
		result += std::to_string(i->value) + " ";
		return result;
	}
	else
		return "no elements to show!";
}